﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.Windows.Input;
using Peter.Common;
using Peter.Common.MainMenu;
using Peter.Sdw.Data;
using Peter.Sdw.Properties;

namespace Peter.Sdw.Logic
{
   /// <summary>
   /// Represents a light from SDW.
   /// </summary>
   public sealed class LightModel : PeterDocument
   {
      private string m_Name;
      private bool m_IsLoading;
      private bool m_ShowInLibrary;
      private bool m_ShowInGlossary;
      private LoveModel m_SelectedLove;
      private RelayCommand m_CmdAddTruth;
      private const string NEW_LIGHT = "New Light";
      private readonly ObservableCollection <LoveModel> m_Loves = new ObservableCollection <LoveModel> ();
      private readonly ObservableCollection <LoveType> m_LoveTypes = new ObservableCollection <LoveType> ();

      /// <summary>
      /// Initializes a new light.
      /// </summary>
      public LightModel ()
      {
         this.Title = NEW_LIGHT;
         this.Icon = MainMenuIcon.LightbulbIdea;
         WebQueue.Instance.WebGetComplete += this.OnGetCompleted;
         WebQueue.Instance.WebPostComplete += this.OnPostCompleted;
         WebQueue.Instance.Get (Constants.URL_GET_LOVE_TYPES);
      }

      /// <summary>
      /// Gets or Sets the id.
      /// </summary>
      public int Id { get; set; }

      /// <summary>
      /// Gets or Sets the name.
      /// </summary>
      public string Name
      {
         get { return this.m_Name; }
         set
         {
            this.m_Name = value;
            this.Title = value;
            this.RaisePropertyChanged ("Name");
            this.Edit ();
         }
      }

      /// <summary>
      /// Gets or Sets if we should show in the library.
      /// </summary>
      public bool ShowInLibrary
      {
         get { return this.m_ShowInLibrary; }
         set
         {
            this.m_ShowInLibrary = value;
            this.RaisePropertyChanged ("ShowInLibrary");
            this.Edit ();
         }
      }

      /// <summary>
      /// Gets or Sets if we should show in the glossary.
      /// </summary>
      public bool ShowInGlossary
      {
         get { return this.m_ShowInGlossary; }
         set
         {
            this.m_ShowInGlossary = value;
            this.RaisePropertyChanged ("ShowInGlossary");
            this.Edit ();
         }
      }

      /// <summary>
      /// Gets or Sets if we are loading data.
      /// </summary>
      public bool IsLoading
      {
         get { return this.m_IsLoading; }
         set
         {
            this.m_IsLoading = value;
            this.RaisePropertyChanged ("IsLoading");
         }
      }

      /// <summary>
      /// Gets the list of loves.
      /// </summary>
      public ObservableCollection<LoveModel> Loves { get { return this.m_Loves; } }

      /// <summary>
      /// Gets the available types of love.
      /// </summary>
      public ObservableCollection<LoveType> LoveTypes { get { return this.m_LoveTypes; } }

      /// <summary>
      /// Gets or Sets if it is ok to send any updates to the server.
      /// </summary>
      public bool OkToUpdate { get; set; }

      /// <summary>
      /// Gets the command used to add truths.
      /// </summary>
      public ICommand AddTruthCommand
      {
         get { return this.m_CmdAddTruth ?? (this.m_CmdAddTruth = new RelayCommand (this.OnAddTruth, this.CanAddTruth)); }
      }

      /// <summary>
      /// Gets or Sets the selected love.
      /// </summary>
      public LoveModel SelectedLove
      {
         get { return this.m_SelectedLove; }
         set
         {
            this.m_SelectedLove = value;
            this.RaisePropertyChanged ("SelectedLove");
            if (this.m_SelectedLove != null)
               this.m_SelectedLove.GetTruth ();
         }
      }

      /// <summary>
      /// Gets the loves (links) to this light.
      /// </summary>
      public void GetLove ()
      {
         if (this.Id > 0) {
            this.IsLoading = true;
            this.Loves.Clear ();
            WebQueue.Instance.Get (string.Format (Constants.URL_GET_LOVE, this.Id));
         }
      }

      /// <summary>
      /// Checks to see if we can add some truth.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      /// <returns>True if we can add, otherwise false.</returns>
      private bool CanAddTruth (object obj)
      {
         return this.SelectedLove != null;
      }

      /// <summary>
      /// Initiates the add truth process.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnAddTruth (object obj)
      {
         var editor = this.Peter.NewFile ();
         editor.Title = "Add Truth";
         editor.Icon = MainMenuIcon.Noteslist;
         var addContent = new EditorEditEntriesModel { Editor = editor };
         editor.RightContent = addContent;
         addContent.AddRequested += this.OnAddTruthList;
      }

      private void OnAddTruthList (object sender, EventArgs e)
      {
         
      }

      /// <summary>
      /// Posts edit data to the server.
      /// </summary>
      private void Edit ()
      {
         if (!this.OkToUpdate || string.IsNullOrEmpty (this.Name)) return;
         var parameters = new NameValueCollection {
            {Constants.REQUEST_TOKEN, WebQueue.Instance.RequestToken},
            {"id", this.Id.ToString (CultureInfo.InvariantCulture)},
            {"name", this.Name},
            {"showInLibrary", this.ShowInLibrary.ToString ()},
            {"showInGlossary", this.ShowInGlossary.ToString ()}
         };
         WebQueue.Instance.Post (this.Id == 0 ? Constants.URL_CREATE_LIGHT : Constants.URL_EDIT_LIGHT, parameters);
      }

      /// <summary>
      /// Occurs when a web get request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnGetCompleted (object sender, WebRequestEventArgs e)
      {
         if (e.Url == string.Format (Constants.URL_GET_LOVE, this.Id)) {
            if (e.Response.status == Constants.SUCCESS) {
               foreach (var love in e.Response.loves) {
                  this.Loves.Add (new LoveModel {
                     Id = love.id,
                     Parent = this,
                     LoveType = love.type,
                     ChildId = love.childId,
                     ChildName = love.childName
                  });
               }
               foreach (var love in this.Loves) {
                  love.OkToUpdate = true;
               }
            }
         }
      }

      /// <summary>
      /// Occurs when a web post request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnPostCompleted (object sender, WebRequestEventArgs e)
      {
         try {
            if (e.Url == Constants.URL_CREATE_LIGHT) {
               if (e.Response.status == Constants.SUCCESS) {
                  Console.WriteLine (@"{0} - {1}", e.Url, Resources.Create_successful);
                  this.Id = e.Response.id;
               }
            } else if (e.Url == Constants.URL_EDIT_LIGHT) {
               if (e.Response.status == Constants.SUCCESS)
                  Console.WriteLine (@"{0} - {1}", e.Url, Resources.Edit_successful);
            }
         } catch (Exception ex) {
            Console.WriteLine (ex.Message);
         }
      }

      /// <summary>
      /// Closes the current item.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      protected override void OnClose (object obj)
      {
         WebQueue.Instance.WebGetComplete -= this.OnGetCompleted;
         WebQueue.Instance.WebPostComplete -= this.OnPostCompleted;
         foreach (var loveModel in this.Loves) {
            loveModel.Dispose ();
         }
         base.OnClose (obj);
      }
   }
}
